url] etc.
// Note : complique car c'est ici qu'on applique typo(),
// et en plus on veut pouvoir les passer en pipeline
//
function inc_lien_dist($lien, $texte='', $class='', $title='', $hlang='', $rel='', $connect='', $env=array()) {
static $u=null;
if (!$u) $u=url_de_base();
$typo = false;
// Si une langue est demandee sur un raccourci d'article, chercher
// la traduction ;
// - [{en}->art2] => traduction anglaise de l'article 2, sinon art 2
// - [{}->art2] => traduction en langue courante de l'art 2, sinon art 2
// s'applique a tout objet traduit
if ($hlang
AND $match = typer_raccourci($lien)) {
@list($type,,$id,,$args,,$ancre) = $match;
$trouver_table = charger_fonction('trouver_table', 'base');
$desc = $trouver_table(table_objet($type, $connect),$connect);
if ($desc
AND $id_table_objet = $desc['key']['PRIMARY KEY']) {
$table_objet_sql = $desc['table'];
if ($row=sql_fetsel('*', $table_objet_sql, "$id_table_objet=".intval($id))
AND isset($row['id_trad'])
AND isset($row['lang'])
AND $id_dest = sql_getfetsel($id_table_objet, $table_objet_sql,"id_trad=".intval($row['id_trad'])." AND lang=" . sql_quote($hlang))
AND objet_test_si_publie($type,$id_dest)
)
$lien = "$type$id_dest";
else
$hlang = '';
}
else
$hlang = '';
}
$mode = ($texte AND $class) ? 'url' : 'tout';
$lien = calculer_url($lien, $texte, $mode, $connect);
if ($mode === 'tout') {
$texte = $lien['titre'];
if (!$class AND isset($lien['class'])) $class = $lien['class'];
$lang = isset($lien['lang']) ?$lien['lang'] : '';
$mime = isset($lien['mime']) ? " type='".$lien['mime']."'" : "";
$lien = $lien['url'];
}
$lien = trim($lien);
if (strncmp($lien,"#",1) == 0) # ancres pures (internes a la page)
$class = 'spip_ancre';
elseif (strncasecmp($lien,'mailto:',7)==0) # pseudo URL de mail
$class = "spip_mail";
elseif (strncmp($texte,'',6)==0) # cf traiter_lien_explicite
$class = "spip_url spip_out";
elseif (!$class) $class = "spip_out"; # si pas spip_in|spip_glossaire
// Si l'objet n'est pas de la langue courante, on ajoute hreflang
if (!$hlang AND $lang!==$GLOBALS['spip_lang'])
$hlang = $lang;
$lang = ($hlang ? " hreflang='$hlang'" : '');
if ($title)
$title = ' title="'.attribut_html($title).'"';
else
$title = ''; // $title peut etre 'false'
// rel=external pour les liens externes
if ((strncmp($lien,'http://',7)==0 OR strncmp($lien,'https://',8)==0)
AND strncmp("$lien/", $u ,strlen($u))!=0)
$rel = trim("$rel external");
if ($rel) $rel = " rel='$rel'";
// si pas de modele dans le texte du lien, on peut juste passer typo sur le texte, c'est plus rapide
// les rares cas de lien qui encapsule un modele passe en dessous, c'est plus lent
if (traiter_modeles($texte, false, '', $connect, null, $env)==$texte){
$texte = typo($texte, true, $connect, $env);
$lien = "$texte";
return $lien;
}
# ceci s'execute heureusement avant les tableaux et leur "|".
# Attention, le texte initial est deja echappe mais pas forcement
# celui retourne par calculer_url.
# Penser au cas [->URL], qui exige typo('...')
$lien = "$texte";
$res = typo($lien, true, $connect, $env);
// dans ce cas, echapons le resultat du modele pour que propre etc ne viennent pas pouicher le html
$res = echappe_html("$res");
return $res;
}
// Regexp des raccourcis, aussi utilisee pour la fusion de sauvegarde Spip
// Laisser passer des paires de crochets pour la balise multi
// mais refuser plus d'imbrications ou de mauvaises imbrications
// sinon les crochets ne peuvent plus servir qu'a ce type de raccourci
define('_RACCOURCI_LIEN', "/\[([^][]*?([[][^]>-]*[]][^][]*)*)->(>?)([^]]*)\]/msS");
// http://code.spip.net/@expanser_liens
function expanser_liens($t, $connect='', $env=array())
{
$t = pipeline('pre_liens', $t);
expanser_un_lien($connect,'init', $env);
if (strpos($t, '->') !== false)
$t = preg_replace_callback (_RACCOURCI_LIEN, 'expanser_un_lien',$t);
// on passe a traiter_modeles la liste des liens reperes pour lui permettre
// de remettre le texte d'origine dans les parametres du modele
$t = traiter_modeles($t, false, false, $connect, expanser_un_lien('','sources'), $env);
$t = corriger_typo($t);
$t = expanser_un_lien($t,'reinsert');
return $t;
}
function expanser_un_lien($reg, $quoi='echappe', $env=null){
static $pile = array();
static $inserts;
static $sources;
static $regs;
static $k = 0;
static $lien;
static $connect='';
static $contexte = array();
switch ($quoi){
case 'init':
if (!$lien) $lien = charger_fonction('lien', 'inc');
if (!is_null($env))
$contexte = $env;
array_push($pile,array($inserts,$sources,$regs,$connect,$k));
$inserts = $sources = $regs = array();
$connect = $reg; // stocker le $connect pour les appels a inc_lien_dist
$k=0;
return;
break;
case 'echappe':
$inserts[$k] = '@@SPIP_ECHAPPE_LIEN_' . $k . '@@';
$sources[$k] = $reg[0];
#$titre=$reg[1];
list($titre, $bulle, $hlang) = traiter_raccourci_lien_atts($reg[1]);
$r = end($reg);
// la mise en lien automatique est passee par la a tort !
// corrigeons pour eviter d'avoir un dans un href...
if (strncmp($r,'...]
// la langue et la bulle eventuelles : [texte|title{lang}->...]
// accepte un niveau de paire de crochets dans le texte :
// [texte[]|title{lang}->...]
// mais refuse
// [texte[|title{lang}->...]
// pour ne pas confondre avec un autre raccourci
define('_RACCOURCI_ATTRIBUTS', '/^((?:[^[]*?(?:\[[^]]*\])?)*?)([|]([^<>]*?))?([{]([a-z_]*)[}])?$/');
// http://code.spip.net/@traiter_raccourci_lien_atts
function traiter_raccourci_lien_atts($texte) {
$bulle = $hlang = false;
// title et hreflang donnes par le raccourci ?
if (strpbrk($texte, "|{") !== false AND
preg_match(_RACCOURCI_ATTRIBUTS, $texte, $m)) {
$n =count($m);
// |infobulle ?
if ($n > 2) {
$bulle = $m[3];
// {hreflang} ?
if ($n > 4) {
// si c'est un code de langue connu, on met un hreflang
if (traduire_nom_langue($m[5]) <> $m[5]) {
$hlang = $m[5];
} elseif (!$m[5]) {
$hlang = test_espace_prive() ?
$GLOBALS['lang_objet'] : $GLOBALS['spip_lang'];
// sinon c'est un italique
} else {
$m[1] .= $m[4];
}
// S'il n'y a pas de hreflang sous la forme {}, ce qui suit le |
// est peut-etre une langue
} else if (preg_match('/^[a-z_]+$/', $m[3])) {
// si c'est un code de langue connu, on met un hreflang
// mais on laisse le title (c'est arbitraire tout ca...)
if (traduire_nom_langue($m[3]) <> $m[3]) {
$hlang = $m[3];
}
}
}
$texte = $m[1];
}
return array(trim($texte), $bulle, $hlang);
}
define('_EXTRAIRE_DOMAINE', '/^(?:(?:[^\W_]((?:[^\W_]|-){0,61}[^\W_,])?\.)+[a-z0-9]{2,6}|localhost)\b/Si');
define('_RACCOURCI_CHAPO', '/^(\W*)(\W*)(\w*\d+([?#].*)?)$/');
/**
* Fonction pour les champs virtuels de redirection qui peut etre:
* 1. un raccourci Spip habituel (premier If) [texte->TYPEnnn]
* 2. un ultra raccourci TYPEnnn voire nnn (article) (deuxieme If)
* 3. une URL std
*
* renvoie l'url reelle de redirection si le $url=true,
* l'url brute contenue dans le chapo sinon
*
* http://code.spip.net/@chapo_redirige
*
* @param string $virtuel
* @param bool $url
* @return string
*/
function virtuel_redirige($virtuel, $url=false){
if (!strlen($virtuel)) return '';
if (!preg_match(_RACCOURCI_LIEN, $virtuel, $m))
if (!preg_match(_RACCOURCI_CHAPO, $virtuel, $m))
return $virtuel;
return !$url ? $m[3] : traiter_lien_implicite($m[3]);
}
// Cherche un lien du type [->raccourci 123]
// associe a une fonction generer_url_raccourci() definie explicitement
// ou implicitement par le jeu de type_urls courant.
//
// Valeur retournee selon le parametre $pour:
// 'tout' : tableau d'index url,class,titre,lang (vise T)
// 'titre': seulement T ci-dessus (i.e. le TITRE ci-dessus ou dans table SQL)
// 'url': seulement U (i.e. generer_url_RACCOURCI)
// http://code.spip.net/@calculer_url
function calculer_url ($ref, $texte='', $pour='url', $connect='', $echappe_typo = true) {
$r = traiter_lien_implicite($ref, $texte, $pour, $connect, $echappe_typo);
$r = ($r ? $r : traiter_lien_explicite($ref, $texte, $pour, $connect, $echappe_typo));
return $r;
}
define('_EXTRAIRE_LIEN', ",^\s*(http:?/?/?|mailto:?)\s*$,iS");
// http://code.spip.net/@traiter_lien_explicite
function traiter_lien_explicite ($ref, $texte='', $pour='url', $connect='', $echappe_typo = true)
{
if (preg_match(_EXTRAIRE_LIEN, $ref))
return ($pour != 'tout') ? '' : array('','','','');
$lien = entites_html(trim($ref));
// Liens explicites
if (!$texte) {
$texte = str_replace('"', '', $lien);
static $lien_court;
// evite l'affichage de trop longues urls.
if (!$lien_court)
$lien_court = charger_fonction('lien_court', 'inc');
$texte = $lien_court($texte);
if ($echappe_typo){
$texte = "".quote_amp($texte)."";
}
}
// petites corrections d'URL
if (preg_match('/^www\.[^@]+$/S',$lien))
$lien = "http://".$lien;
else if (strpos($lien, "@") && email_valide($lien)) {
if (!$texte) $texte = $lien;
$lien = "mailto:".$lien;
}
if ($pour == 'url') return $lien;
if ($pour == 'titre') return $texte;
return array('url' => $lien, 'titre' => $texte);
}
function liens_implicite_glose_dist($texte,$id,$type,$args,$ancre,$connect=''){
if ( ($ancre AND function_exists($f = 'glossaire_' . $ancre))
OR function_exists($f = 'glossaire_'))
$url = $f($texte, $id, $ancre);
else
$url = glossaire_std($texte);
return $url;
}
/**
* Transformer un lien raccourci art23 en son URL
* Par defaut la fonction produit une url prive si on est dans le prive
* ou publique si on est dans le public.
* La globale lien_implicite_cible_public permet de forcer un cas ou l'autre :
* $GLOBALS['lien_implicite_cible_public'] = true;
* => tous les liens raccourcis pointent vers le public
* $GLOBALS['lien_implicite_cible_public'] = false;
* => tous les liens raccourcis pointent vers le prive
* unset($GLOBALS['lien_implicite_cible_public']);
* => retablit le comportement automatique
*
* http://code.spip.net/@traiter_lien_implicite
*
* @param string $ref
* @param string $texte
* @param string $pour
* @param string $connect
* @return array|bool|string
*/
function traiter_lien_implicite ($ref, $texte='', $pour='url', $connect='')
{
$cible = ($connect ? $connect : (isset($GLOBALS['lien_implicite_cible_public'])?$GLOBALS['lien_implicite_cible_public']:null));
if (!($match = typer_raccourci($ref))) return false;
@list($type,,$id,,$args,,$ancre) = $match;
# attention dans le cas des sites le lien doit pointer non pas sur
# la page locale du site, mais directement sur le site lui-meme
$url = '';
if ($f = charger_fonction("implicite_$type","liens",true))
$url = $f($texte,$id,$type,$args,$ancre,$connect);
if (!$url)
$url = generer_url_entite($id,$type,$args,$ancre,$cible);
if (!$url) return false;
if (is_array($url)) {
@list($type,$id) = $url;
$url = generer_url_entite($id,$type,$args,$ancre,$cible);
}
if ($pour === 'url') return $url;
$r = traiter_raccourci_titre($id, $type, $connect);
if ($r) $r['class'] = ($type == 'site')?'spip_out':'spip_in';
if ($texte = trim($texte)) $r['titre'] = $texte;
if (!@$r['titre']) $r['titre'] = _T($type) . " $id";
if ($pour=='titre') return $r['titre'];
$r['url'] = $url;
// dans le cas d'un lien vers un doc, ajouter le type='mime/type'
if ($type == 'document'
AND $mime = sql_getfetsel('mime_type', 'spip_types_documents',
"extension IN (".sql_get_select("extension","spip_documents","id_document=".sql_quote($id)).")",
'','','','',$connect)
)
$r['mime'] = $mime;
return $r;
}
// analyse des raccourcis issus de [TITRE->RACCOURCInnn] et connexes
define('_RACCOURCI_URL', '/^\s*(\w*?)\s*(\d+)(\?(.*?))?(#([^\s]*))?\s*$/S');
// http://code.spip.net/@typer_raccourci
function typer_raccourci ($lien) {
if (!preg_match(_RACCOURCI_URL, $lien, $match)) return array();
$f = $match[1];
// valeur par defaut et alias historiques
if (!$f) $f = 'article';
else if ($f == 'art') $f = 'article';
else if ($f == 'br') $f = 'breve';
else if ($f == 'rub') $f = 'rubrique';
else if ($f == 'aut') $f = 'auteur';
else if ($f == 'doc' OR $f == 'im' OR $f == 'img' OR $f == 'image' OR $f == 'emb')
$f = 'document';
else if (preg_match('/^br..?ve$/S', $f)) $f = 'breve'; # accents :(
$match[0] = $f;
return $match;
}
// Retourne le champ textuel associe a une cle primaire, et sa langue
function traiter_raccourci_titre($id, $type, $connect=NULL)
{
$trouver_table = charger_fonction('trouver_table', 'base');
$desc = $trouver_table(table_objet($type));
if (!($desc AND $s = $desc['titre'])) return array();
$_id = $desc['key']['PRIMARY KEY'];
$r = sql_fetsel($s, $desc['table'], "$_id=$id", '','','','',$connect);
if (!$r) return array();
$r['titre'] = supprimer_numero($r['titre']);
if (!$r['titre']) $r['titre'] = $r['surnom'];
if (!isset($r['lang'])) $r['lang'] = '';
return $r;
}
// traite les modeles (dans la fonction typo), en remplacant
// le raccourci par la page calculee a
// partir du squelette modeles/modele.html
// Le nom du modele doit faire au moins trois caracteres (evite